package com.wanlian.socketserver.Device.worker;

import com.wanlian.common.KeyPara;
import com.wanlian.entity.Device;
import com.wanlian.entity.DeviceData;
import com.wanlian.json.JsonStringUtil;
import com.wanlian.model.ResultModel;
import com.wanlian.netty.model.Address;
import com.wanlian.netty.model.ChannelInfo;
import com.wanlian.socketserver.Device.DeviceOnline;
import com.wanlian.socketserver.Device.ServerConfig;
import com.wanlian.socketserver.Device.worker.DeviceServerWorker;
import com.wanlian.util.DateUtil;
import com.wanlian.util.HttpUtils;
import com.wanlian.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;

public class OnlineWorker implements Runnable {

    @Autowired
    private ServerConfig serverConfig;

    private static Map<String, DeviceData> srcDeviceDataMap = new HashMap<>();
    //private static String SET_ONLINE_URL_LIST = "http://localhost:8080/wanlian.candy/device/updonline/list";
    private BlockingQueue queue;

    public OnlineWorker(BlockingQueue queue) {
        getAllDeviceOnlineData();
        this.queue = queue;
    }

    @Override
    public void run() {
        try {

            while (true) {
                try {
                    processOnlineRouter();
                    Thread.sleep(2 * 1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {

        } finally {
            System.out.println("生产者退出线程");
        }
    }

    private synchronized void processOnlineRouter() {
        try {
            Map<String, String> needToRemoveMap = new HashMap<>();
            Map<String, Integer> needToRefrushMap = new HashMap<>();
            Map<String, String> maps = DeviceServerWorker.sessionPool.copyMap();
            for (String key : maps.keySet()) {
                if (DeviceServerWorker.sessionPool.publicKeyChannelMap.containsKey(key)) {
                    ChannelInfo channelInfo = DeviceServerWorker.sessionPool.publicKeyChannelMap.get(key);
                    long timeSpan = DateUtil.currentTimestamp().getTime() - channelInfo.getLastConnectTime().getTime();
                    if (!DateUtil.isSameDay(channelInfo.getFirstTime(), DateUtil.currentDateTimestamp())) {
                        channelInfo.setFirstTime(DateUtil.currentTimestamp());
                    }
                    long timeSecond = (DateUtil.currentTimestamp().getTime() - channelInfo.getFirstTime().getTime()) / 1000;
                    calRouterTime(key, (int) timeSecond);
                    if (timeSpan > 10 * 1000) {
                        System.out.println("current:" + DateUtil.currentDatetime() + " last:" + DateUtil.getTimeByTimestamp(channelInfo.getLastConnectTime()));
                        needToRemoveMap.put(key, key);
                    } else {
                        int totalSecond = srcDeviceDataMap.get(key).getOnlineTime();
                        needToRefrushMap.put(key, totalSecond);
                    }
                }
            }
            processOnline(needToRefrushMap);
            processOffline(needToRemoveMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private synchronized void processOnline(Map<String, Integer> needToRefrushMap) {
        Map<String, Address> routers = DeviceServerWorker.sessionPool.getAllRouter();
        List<Device> deviceOnlines = new ArrayList<>();
        if (needToRefrushMap.size() > 0) {
            for (String key : needToRefrushMap.keySet()) {
                Device device = new Device();
                device.setDevicekey(key);
                if (routers.containsKey(key)) {
                    device.setVersion(routers.get(key).getVersion());
                    deviceOnlines.add(device);
                }
            }
            if (deviceOnlines.size() > 0) {
                refrushPeersTime(needToRefrushMap);
                setOnline(deviceOnlines);
            }
        }
    }

    private synchronized void processOffline(Map<String, String> needToRemoveMap) {
        Map<String, Address> routers = DeviceServerWorker.sessionPool.getAllRouter();
        List<Device> devices = new ArrayList<>();
        if (needToRemoveMap.size() > 0) {
            for (String key : needToRemoveMap.keySet()) {
                Device device = new Device();
                device.setDevicekey(key);
                if (routers.containsKey(key)) {
                    device.setVersion(routers.get(key).getVersion());
                    devices.add(device);
                }
            }
            if (devices.size() > 0) {
                setOffline(devices);
            }
            DeviceServerWorker.sessionPool.removeSessionByMap(needToRemoveMap);
        }
    }


    public void getAllDeviceOnlineData() {
        try {
            String data = HttpUtils.sendPost(serverConfig.datatoday, "");
            if (StringUtil.hasValue(data)) {
                ResultModel resultModel = JsonStringUtil.readValue(data, ResultModel.class);
                if (resultModel != null && resultModel.getObject() != null) {
                    data = (String) resultModel.getObject();
                    List<DeviceData> list = JsonStringUtil.readValueByList(data, DeviceData.class);
                    for (DeviceData item : list) {
                        if (!srcDeviceDataMap.containsKey(item.getDeviceKey())) {
                            srcDeviceDataMap.put(item.getDeviceKey(), item);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 保存延时方法
     *
     * @param key
     */
    private static void calRouterTime(String key, int second) {
        if (srcDeviceDataMap.containsKey(key)) {
            DeviceData deviceData = srcDeviceDataMap.get(key);
            if (!DateUtil.isSameDay(deviceData.getModifyTime(), DateUtil.currentDateTimestamp())) {
                deviceData.setOnlineTime(0);
                deviceData.setModifyTime(DateUtil.currentDateTimestamp());
            } else {
                deviceData.setOnlineTime(second);
            }
        } else {
            DeviceData deviceData = new DeviceData();
            deviceData.setDeviceKey(key);
            deviceData.setModifyTime(DateUtil.currentDateTimestamp());
            deviceData.setOnlineTime(second);
            srcDeviceDataMap.put(key, deviceData);
        }
    }

    private void refrushPeersTime(Map<String, Integer> peerTimes) {
        List<DeviceData> deviceDataList = new ArrayList<>();
        for (String key : peerTimes.keySet()) {
            DeviceData deviceData = new DeviceData();
            deviceData.setDeviceKey(key);
            deviceData.setModifyTime(DateUtil.currentDateTimestamp());
            deviceData.setMaxBw(5);
            deviceData.setOnlineTime(peerTimes.get(key));
            deviceDataList.add(deviceData);
        }
        if (deviceDataList.size() > 0) {
            KeyPara para = new KeyPara(serverConfig.devicedatalist, JsonStringUtil.writeValueAsString(deviceDataList));
            queue.offer(para);
        }
    }


    public void setOnline(List<Device> devices) {
        if (devices.size() > 0) {
            List<DeviceOnline> deviceOnlines = new ArrayList<>();
            for (Device item : devices) {
                DeviceOnline deviceOnline = new DeviceOnline();
                deviceOnline.setDevicekey(item.getDevicekey());
                deviceOnline.setOnline(true);
                deviceOnline.setVersion(item.getVersion());
                deviceOnlines.add(deviceOnline);
            }

            KeyPara para = new KeyPara(serverConfig.urllist, JsonStringUtil.writeValueAsString(deviceOnlines));
            queue.offer(para);
        }
    }

    public void setOffline(List<Device> devices) {
        if (devices.size() > 0) {
            List<DeviceOnline> deviceOnlines = new ArrayList<>();
            for (Device item : devices) {
                DeviceOnline deviceOnline = new DeviceOnline();
                deviceOnline.setDevicekey(item.getDevicekey());
                deviceOnline.setOnline(false);
                deviceOnline.setVersion(item.getVersion());
                deviceOnlines.add(deviceOnline);
            }
            KeyPara para = new KeyPara(serverConfig.urllist, JsonStringUtil.writeValueAsString(deviceOnlines));
            queue.offer(para);
        }
    }
}
